Fix VIRQ_TIMER holdoff for SMP guests.
Signed-off-by: Keir Fraser <keir@xensource.com>
{
u64 alarm = 0;
int ret = 0;
+ unsigned long j;
#ifdef CONFIG_SMP
unsigned long seq;
#endif
#ifdef CONFIG_SMP
do {
seq = read_seqbegin(&xtime_lock);
- if (smp_processor_id())
- alarm = __jiffies_to_st(jiffies + 1);
- else
- alarm = __jiffies_to_st(jiffies + 1);
+ j = jiffies + 1;
+ alarm = __jiffies_to_st(j);
} while (read_seqretry(&xtime_lock, seq));
#else
- alarm = __jiffies_to_st(next_timer_interrupt());
+ j = next_timer_interrupt();
+ if (j < (jiffies + 1))
+ j = jiffies + 1;
+ alarm = __jiffies_to_st(j);
#endif
/* Failure is pretty bad, but we'd best soldier on. */
}
#ifdef CONFIG_SMP
-#define xxprint(msg) HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg)
static irqreturn_t local_timer_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
#endif
}
- if (smp_processor_id() == 0) {
- xxprint("bug bug\n");
- BUG();
- }
-
return IRQ_HANDLED;
}
+ return now;
+}
+
-+int update_dom_time(struct exec_domain *ed)
++void update_dom_time(struct exec_domain *ed)
+{
+// FIXME: implement this?
+// printf("update_dom_time: called, not implemented, skipping\n");
-+ return 0;
++ return;
+}
+
+/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
spin_unlock(&d->time_lock);
}
-int update_dom_time(struct exec_domain *ed)
+void update_dom_time(struct exec_domain *ed)
{
unsigned long flags;
- if ( ed->domain->shared_info->tsc_timestamp == full_tsc_irq )
- return 0;
-
- read_lock_irqsave(&time_lock, flags);
- __update_dom_time(ed);
- read_unlock_irqrestore(&time_lock, flags);
-
- return 1;
+ if ( ed->domain->shared_info->tsc_timestamp != full_tsc_irq )
+ {
+ read_lock_irqsave(&time_lock, flags);
+ __update_dom_time(ed);
+ read_unlock_irqrestore(&time_lock, flags);
+ }
}
/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
/**
* ATROPOS - main scheduler function
*/
-task_slice_t ksched_scheduler(s_time_t time)
+struct task_slice ksched_scheduler(s_time_t time)
{
struct domain *cur_sdom = current; /* Current sdom */
s_time_t newtime;
struct at_dom_info *cur_info;
static unsigned long waitq_rrobin = 0;
int i;
- task_slice_t ret;
+ struct task_slice ret;
cur_info = DOM_INFO(cur_sdom);
* i.e., the domain with lowest EVT.
* The runqueue should be ordered by EVT so that is easy.
*/
-static task_slice_t bvt_do_schedule(s_time_t now)
+static struct task_slice bvt_do_schedule(s_time_t now)
{
struct domain *d;
struct exec_domain *prev = current, *next = NULL, *next_prime, *ed;
struct bvt_edom_info *p_einf = NULL;
struct bvt_edom_info *next_einf = NULL;
struct bvt_edom_info *next_prime_einf = NULL;
- task_slice_t ret;
+ struct task_slice ret;
ASSERT(prev->ed_sched_priv != NULL);
ASSERT(prev_einf != NULL);
}
/* Main scheduling function */
-static task_slice_t rr_do_schedule(s_time_t now)
+static struct task_slice rr_do_schedule(s_time_t now)
{
struct domain *prev = current;
int cpu = current->processor;
- task_slice_t ret;
+ struct task_slice ret;
if ( !is_idle_task(prev) )
{
*
*/
+/*#define WAKE_HISTO*/
+/*#define BLOCKTIME_HISTO*/
+
+#if defined(WAKE_HISTO)
+#define BUCKETS 31
+#elif defined(BLOCKTIME_HISTO)
+#define BUCKETS 200
+#endif
+
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
static char opt_sched[10] = "bvt";
string_param("sched", opt_sched);
-/*#define WAKE_HISTO*/
-/*#define BLOCKTIME_HISTO*/
-
-#if defined(WAKE_HISTO)
-#define BUCKETS 31
-#elif defined(BLOCKTIME_HISTO)
-#define BUCKETS 200
-#endif
-
#define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */
/*
static void dom_timer_fn(unsigned long data);
/* This is global for now so that private implementations can reach it */
-schedule_data_t schedule_data[NR_CPUS];
+struct schedule_data schedule_data[NR_CPUS];
extern struct scheduler sched_bvt_def;
// extern struct scheduler sched_rrobin_def;
struct exec_domain *prev = current, *next = NULL;
int cpu = prev->processor;
s_time_t now;
- task_slice_t next_slice;
+ struct task_slice next_slice;
s32 r_time; /* time for new dom to run */
perfc_incrc(sched_run);
TRACE_2D(TRC_SCHED_SWITCH, next->domain->id, next);
+ prev->sleep_tick = schedule_data[cpu].tick;
+
/* Ensure that the domain has an up-to-date time base. */
- if ( !is_idle_task(next->domain) && update_dom_time(next) )
- send_guest_virq(next, VIRQ_TIMER);
+ if ( !is_idle_task(next->domain) )
+ {
+ update_dom_time(next);
+ if ( next->sleep_tick != schedule_data[cpu].tick )
+ send_guest_virq(next, VIRQ_TIMER);
+ }
context_switch(prev, next);
}
* - dom_timer: per domain timer to specifiy timeout values
****************************************************************************/
-/* The scheduler timer: force a run through the scheduler*/
+/* The scheduler timer: force a run through the scheduler */
static void s_timer_fn(unsigned long unused)
{
TRACE_0D(TRC_SCHED_S_TIMER_FN);
perfc_incrc(sched_irq);
}
-/* Periodic tick timer: send timer event to current domain*/
+/* Periodic tick timer: send timer event to current domain */
static void t_timer_fn(unsigned long unused)
{
- struct exec_domain *ed = current;
+ struct exec_domain *ed = current;
+ unsigned int cpu = ed->processor;
TRACE_0D(TRC_SCHED_T_TIMER_FN);
- if ( !is_idle_task(ed->domain) && update_dom_time(ed) )
+ schedule_data[cpu].tick++;
+
+ if ( !is_idle_task(ed->domain) )
+ {
+ update_dom_time(ed);
send_guest_virq(ed, VIRQ_TIMER);
+ }
page_scrub_schedule_work();
- t_timer[ed->processor].expires = NOW() + MILLISECS(10);
- add_ac_timer(&t_timer[ed->processor]);
+ t_timer[cpu].expires = NOW() + MILLISECS(10);
+ add_ac_timer(&t_timer[cpu]);
}
/* Domain timer function, sends a virtual timer interrupt to domain */
struct exec_domain *ed = (struct exec_domain *)data;
TRACE_0D(TRC_SCHED_DOM_TIMER_FN);
- (void)update_dom_time(ed);
+
+ update_dom_time(ed);
send_guest_virq(ed, VIRQ_TIMER);
}
-#include <asm/types.h>
-
-/*
+/******************************************************************************
* Additional declarations for the generic scheduler interface. This should
* only be included by files that implement conforming schedulers.
*
* Portions by Mark Williamson are (C) 2004 Intel Research Cambridge
*/
-#define BUCKETS 10
+#ifndef __XEN_SCHED_IF_H__
+#define __XEN_SCHED_IF_H__
-typedef struct schedule_data_st
-{
- spinlock_t schedule_lock; /* spinlock protecting curr pointer
- TODO check this */
- struct exec_domain *curr; /* current task */
- struct exec_domain *idle; /* idle task for this cpu */
- void * sched_priv;
- struct ac_timer s_timer; /* scheduling timer */
+struct schedule_data {
+ spinlock_t schedule_lock; /* spinlock protecting curr */
+ struct exec_domain *curr; /* current task */
+ struct exec_domain *idle; /* idle task for this cpu */
+ void *sched_priv;
+ struct ac_timer s_timer; /* scheduling timer */
+ unsigned long tick; /* current periodic 'tick' */
#ifdef BUCKETS
u32 hist[BUCKETS]; /* for scheduler latency histogram */
#endif
-} __cacheline_aligned schedule_data_t;
-
+} __cacheline_aligned;
-typedef struct task_slice_st
-{
+struct task_slice {
struct exec_domain *task;
s_time_t time;
-} task_slice_t;
+};
-struct scheduler
-{
+struct scheduler {
char *name; /* full name for this scheduler */
char *opt_name; /* option name for this scheduler */
unsigned int sched_id; /* ID for this scheduler */
void (*sleep) (struct exec_domain *);
void (*wake) (struct exec_domain *);
void (*do_block) (struct exec_domain *);
- task_slice_t (*do_schedule) (s_time_t);
+ struct task_slice (*do_schedule) (s_time_t);
int (*control) (struct sched_ctl_cmd *);
int (*adjdom) (struct domain *,
struct sched_adjdom_cmd *);
int (*prn_state) (int);
};
-/* per CPU scheduler information */
-extern schedule_data_t schedule_data[];
-
+extern struct schedule_data schedule_data[];
+#endif /* __XEN_SCHED_IF_H__ */
#endif
struct ac_timer timer; /* one-shot timer for timeout values */
+ unsigned long sleep_tick; /* tick at which this vcpu started sleep */
s_time_t lastschd; /* time this domain was last scheduled */
s_time_t lastdeschd; /* time this domain was last descheduled */
#define MILLISECS(_ms) (((s_time_t)(_ms)) * 1000000ULL )
#define MICROSECS(_us) (((s_time_t)(_us)) * 1000ULL )
-extern int update_dom_time(struct exec_domain *ed);
-extern void do_settime(unsigned long secs, unsigned long usecs,
- u64 system_time_base);
+extern void update_dom_time(struct exec_domain *ed);
+extern void do_settime(
+ unsigned long secs, unsigned long usecs, u64 system_time_base);
#endif /* __XEN_TIME_H__ */